class Computed {
  constructor() {
    /**
     *total() {
        console.log('computed')
        return 1 + 2
      }
     *
     * {
     *   key: total,
     *   value: 3,
     *   get: total fn,
     *   dep: [a, b]
     * }
     * */
    this.computedData = []
  }
  addComputed(vm, computed, key){
    const descriptor = Object.getOwnPropertyDescriptor(computed, key),
          descriptorFn = descriptor.value.get
                        ? descriptor.value.get
                        : descriptor.value,
          value = descriptorFn.call(vm),
          get = descriptorFn.bind(vm),
          dep = this._collectDep(descriptorFn);
    this._addComputedProp({
      key,
      value,
      get,
      dep
    })
    const dataItem = this.computedData.find(item => key === item.key)
    Object.defineProperty(vm, key , {
      get(){
        return dataItem.value;
      },
      set() {
        dataItem.value = dataItem.get()
      }
    })
  }
  update (key, watcher) {
    this.computedData.map(item => {
      const dep = item.dep
      const _key = dep.find(el => el === key)
      if(_key) {
        const oldValue = item.value
        item.value = item.get()
        watcher(item.key, item.value, oldValue)
      }
    })
  }
  _addComputedProp(computedProp){
   this.computedData.push(computedProp)
  }
  _collectDep(fn){
    const matched = fn.toString().match(/this\.(.+?)/g);
    return matched.map(item => item.split('.')[1])
  }
}

export default Computed
